#ifndef LUA_WRAPER_H
#define LUA_WRAPER_H

#include <string.h>
#include <iostream>
#include<typeinfo>
#include <iostream>
#include <map>

extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}

class LuaDelegate {
public:
    LuaDelegate();
    LuaDelegate(std::map<std::string, lua_CFunction>);

    int DoFile(std::string);
    void Stop();
    int DoString(std::string);
    int UpdateScript(std::string);


	int pushstack(lua_Number arg) {
		lua_pushnumber(mVM, arg);
		return 1;
    }
	int pushstack(lua_Integer arg) {
		lua_pushinteger(mVM, arg);
		return 1;
	}
	int pushstack(void* arg) {
		lua_pushlightuserdata(mVM, arg);
		return 1;
	}
	int pushstack(const char* arg) {
		lua_pushstring(mVM,arg);
		return 1;
	}
	int pushstack(bool arg) {
        lua_pushboolean (mVM, arg);
		return 1;
	}
	int pushstack(std::string arg) {
		lua_pushstring(mVM, arg.c_str());
		return 1;
	}
	int pushstack(lua_CFunction fn, int n) {
		lua_pushcclosure(mVM, fn, n);
		return 1;
	}

    template <typename ... Types>
	int pushstack(lua_Number arg1, Types... rest) {
		lua_pushnumber(mVM, arg1);
		int ret = pushstack(rest...) + 1;
		return ret;
	}
	template <typename ... Types>
	int pushstack(lua_Integer arg1, Types... rest) {
        lua_pushinteger (mVM, arg1);
		int ret =  pushstack(rest...) + 1;
		return ret;
	}
	template <typename ... Types>
	int pushstack(bool arg1, Types... rest) {
		lua_pushboolean(mVM, arg1);
		int ret = pushstack(rest...) + 1;
		return ret;
	}
	template <typename ... Types>
	int pushstack(std::string arg1, Types... rest) {
		lua_pushstring(mVM, arg1.c_str());
		int ret = pushstack(rest...) + 1;
		return ret;
	}
	template <typename ... Types>
	int pushstack(void* arg1, Types... rest) {
		lua_pushlightuserdata(mVM, arg1);
		int ret = pushstack(rest...) + 1;
		return ret;
	}
	template <typename ... Types>
	int pushstack(lua_CFunction fn, int n, Types... rest) {
        lua_pushcclosure(mVM, fn,n);
		int ret = pushstack(rest...) + 1;
		return ret;
	}
	template <typename ... Types>
	int pushstack(const char* arg1, Types... rest) {
		lua_pushstring(mVM, arg1);
		int ret = pushstack(rest...) + 1;
		return ret;
	}
    template<typename... T>
    int CallFuntion(std::string name,T... para){
        int i = lua_getglobal(mVM,name.c_str());
        if(LUA_TNIL == i){
            return -1;
        }
        int ret = pushstack(para...);
		std::cout << "parameter count is " << ret;
		lua_call(mVM, ret, 0);
		return 0;
    }
	lua_State* VM();
    void PrintError(lua_State *L);
	int BindFunction(std::string name, lua_CFunction);
	void OnSerialData(std::string);
    void DumpStack();

    ~LuaDelegate();
private:
    lua_State *mVM;
    std::string mFile;
	std::string mScript;
    std::map<std::string, lua_CFunction> mFunc;
};

#endif 

